﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Net;
using System.Net.Quic;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UMC.Data;
using UMC.Host;
using UMC.Net;
using UMC.ITME.Entities;
using UMC.Web;

namespace UMC.ITME
{
    public class SocketProxyServier
    {
        String host;
        int port;
        ProtocolType protocolType;
        public SocketProxyServier(ProtocolType t, string h, int p)
        {
            this.host = h;
            this.port = p;
            this.protocolType = t;

        }
        class SocketProxy : IDisposable
        {

            byte[] clientData = System.Buffers.ArrayPool<byte>.Shared.Rent(0x200);
            byte[] proxyData = System.Buffers.ArrayPool<byte>.Shared.Rent(0x200);
            public Socket client;
            public Socket proxy;
            SocketAsyncEventArgs clientEventArgs, proxyEventArgs, clientSendArgs, proxySendArgs;

            public SocketProxy(Socket client, Socket proxy)
            {
                this.client = client;
                this.proxy = proxy;
                clientEventArgs = new SocketAsyncEventArgs();
                clientEventArgs.SetBuffer(clientData);

                clientEventArgs.Completed += ClientCompleted;

                proxySendArgs = new SocketAsyncEventArgs();
                proxySendArgs.SetBuffer(clientData);
                proxySendArgs.Completed += ClientCompleted;


                this.proxyEventArgs = new SocketAsyncEventArgs();
                proxyEventArgs.SetBuffer(proxyData);
                proxyEventArgs.Completed += ProxyCompleted;
                clientSendArgs = new SocketAsyncEventArgs();
                clientSendArgs.SetBuffer(proxyData);
                // proxyEventArgs.SetBuffer(proxyData);

                clientSendArgs.Completed += ProxyCompleted;


                if (!this.proxy.ReceiveAsync(proxyEventArgs))
                {
                    ProxyReceive(proxyEventArgs);
                }

                if (!this.client.ReceiveAsync(clientEventArgs))
                {
                    ClientReceive(clientEventArgs);
                }


            }
            private void ProxyCompleted(object sender, SocketAsyncEventArgs e)
            {
                if (e.SocketError == SocketError.Success)
                {
                    switch (e.LastOperation)
                    {
                        case SocketAsyncOperation.Receive:
                            ProxyReceive(e);
                            break;
                        case SocketAsyncOperation.Send:
                            break;

                    }
                }
                else
                {
                    this.Dispose();
                }
            }
            private void ProxyReceive(SocketAsyncEventArgs e)
            {
                if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
                {
                    try
                    {

                        clientSendArgs.SetBuffer(proxyData, e.Offset, e.BytesTransferred);
                        this.client.SendAsync(clientSendArgs);

                        while (!proxy.ReceiveAsync(e))
                        {
                            if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
                            {
                                clientSendArgs.SetBuffer(proxyData, e.Offset, e.BytesTransferred);
                                this.client.SendAsync(clientSendArgs);

                            }
                            else
                            {
                                this.Dispose();
                                break;
                            }
                        }
                    }
                    catch// (Exception ex)
                    {
                        this.Dispose();
                    }
                }
                else
                {
                    this.Dispose();
                }
            }
            private void ClientReceive(SocketAsyncEventArgs e)
            {
                if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
                {
                    try
                    {
                        proxySendArgs.SetBuffer(clientData, e.Offset, e.BytesTransferred);
                        this.proxy.SendAsync(proxySendArgs);

                        while (!client.ReceiveAsync(e))
                        {
                            if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
                            {
                                proxySendArgs.SetBuffer(clientData, e.Offset, e.BytesTransferred);
                                this.proxy.SendAsync(proxySendArgs);

                            }
                            else
                            {
                                this.Dispose();
                                break;
                            }
                        }
                    }
                    catch
                    {
                        this.Dispose();
                    }
                }
                else
                {
                    this.Dispose();
                }
            }
            private void ClientCompleted(object sender, SocketAsyncEventArgs e)
            {
                if (e.SocketError == SocketError.Success)
                {
                    switch (e.LastOperation)
                    {
                        case SocketAsyncOperation.Receive:
                            ClientReceive(e);
                            break;
                    }
                }
                else
                {
                    this.Dispose();
                }
            }

            public void Dispose()
            {
                try
                {
                    this.proxy.Shutdown(SocketShutdown.Both);
                    this.proxy.Close();
                    this.proxy.Dispose();
                }
                catch
                {

                }
                try
                {

                    this.client.Shutdown(SocketShutdown.Both);
                    this.client.Close();
                    this.client.Dispose();
                }
                catch
                {

                }
                System.Buffers.ArrayPool<byte>.Shared.Return(this.clientData);
                System.Buffers.ArrayPool<byte>.Shared.Return(this.proxyData);

                clientEventArgs.Dispose();
                proxyEventArgs.Dispose();
                proxySendArgs.Dispose();
                clientSendArgs.Dispose();

            }
        }
        void Accept(Socket socket)
        {
            var con = new ConnectAsyncEventArgs(protocolType);
            con.Connected = (cline) =>
            {
                new SocketProxy(socket, cline);
                con.Dispose();

            };
            con.Error = (ex) =>
            {
                socket.Shutdown(SocketShutdown.Both);
                // socket.Close();
                socket.Dispose();
                Utility.Error("Server", DateTime.Now, $"{host}:{port}-->{ex.Message}");
                con.Dispose();
            };
            con.Start(5000, host, port);

        }
        public void Accept(object sender, SocketAsyncEventArgs eventArgs)
        {
            if (eventArgs.SocketError == SocketError.Success)
            {

                Accept(eventArgs.AcceptSocket);

                eventArgs.AcceptSocket = null;
                while (!((Socket)sender).AcceptAsync(eventArgs))
                {
                    if (eventArgs.SocketError == SocketError.Success)
                    {
                        Accept(eventArgs.AcceptSocket);
                    }
                    eventArgs.AcceptSocket = null;
                }
            }
        }
    }


    public class HttpMimeServier : IDoWorker
    {
        static String _Server = Dns.GetHostName();
        public static String Server => _Server;

        X509Certificate _certificate;

        X509Certificate DefaultCertificate
        {
            get
            {
                if (this._certificate == null)
                {
                    _certificate = X509Certificate2.CreateFromPem(CertKey, PrivateKey);
                }

                return _certificate;
            }
        }
        X509Certificate ServerCertificateSelectionCallback(object sender, string hostName)
        {
            if (String.IsNullOrEmpty(hostName) == false)
            {
                if (Certificater.Certificates.TryGetValue(hostName, out var x509Certificate))
                {
                    return x509Certificate.Certificate ?? DefaultCertificate;
                }
                else
                {
                    var l = hostName.IndexOf('.');
                    if (l > 0)
                    {
                        var cName = "*" + hostName.Substring(l);
                        if (Certificater.Certificates.TryGetValue(cName, out var x509))
                        {
                            return x509.Certificate ?? DefaultCertificate;
                        }
                        else
                        {
                            var certs = HotCache.Find(new SiteCert { Domain = hostName }, "Domain", new string[] { cName });
                            if (certs?.Length > 0)
                            {
                                var cert = certs[0];

                                if (String.IsNullOrEmpty(cert.PrivateKey) && certs.Length > 1)
                                {
                                    cert = certs[1];
                                }
                                if (String.IsNullOrEmpty(cert.PrivateKey) == false && String.IsNullOrEmpty(cert.PublicKey) == false)
                                {
                                    try
                                    {
                                        var x5092 = X509Certificate2.CreateFromPem(cert.PublicKey, cert.PrivateKey);
                                        Certificater.Certificates[cert.Domain] = new Certificater
                                        {
                                            Name = cert.Domain,
                                            Certificate = x5092
                                        };
                                        return x5092;
                                    }
                                    catch
                                    {
                                    }
                                }
                                // }
                                // else
                                // {
                                //     SignSSL(hostName);
                            }
                        }
                    }
                }
            }
            return DefaultCertificate;
        }

        SslServerAuthenticationOptions sslServerAuthentication;
        Dictionary<int, Socket[]> _host = new Dictionary<int, Socket[]>();
        Socket BindSocket(IPEndPoint point, EventHandler<SocketAsyncEventArgs> Completed)
        {
            return BindSocket(point, ProtocolType.Tcp, Completed);
        }

        Socket BindSocket(IPEndPoint point, ProtocolType protocolType, EventHandler<SocketAsyncEventArgs> Completed)
        {
            var socket = new Socket(point.Address.AddressFamily, protocolType == ProtocolType.Udp ? SocketType.Dgram : SocketType.Stream, protocolType);
            socket.Bind(point);
            socket.Listen(512);
            SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs();
            eventArgs.Completed += Completed;
            socket.AcceptAsync(eventArgs);
            return socket;
            // eventArgs.SetBuffer
        }
        public static void SignSSL(String hostName)
        {
            if (hostName.StartsWith("www.") == false && CheckSSL(hostName))
            {

                var secret = UMC.Data.WebResource.Instance().Provider["appSecret"];
                if (String.IsNullOrEmpty(secret) == false)
                {
                    HotCache.Put(new SiteCert
                    {
                        Domain = hostName,
                        ExpirationTime = 0,
                        CheckTime = Utility.TimeSpan()
                    });

                    CheckSSl(secret, hostName, true);
                }
            }
        }
        public static bool CheckSSL(String host)
        {
            var mainHost = UMC.ITME.WebServlet.MainDomain;
            if (mainHost == host)
            {
                return true;
            }
            if (host.Length > mainHost.Length && host.EndsWith(mainHost))
            {
                var rook = host.Substring(0, host.Length - mainHost.Length - 1);
                var ls = rook.Split('.');
                if (ls.Length > 1)
                {

                    var siteConfig = UMC.ITME.DataFactory.Instance().Site(ls[ls.Length - 1]);
                    if (siteConfig != null)
                    {
                        return ls[0] == "www";
                    }
                    return false;
                }
                else if (UMC.ITME.DataFactory.Instance().Site(ls[0]) != null)
                {
                    return true;

                }
                else if (String.Equals(ls[0], Data.WebResource.Instance().Provider["auth"]))
                {
                    return true;
                }
            }

            return UMC.ITME.DataFactory.Instance().Host(host) != null;
        }
        List<String> _urls = new List<string>();
        public const String UnixPath = @"/tmp/umc.unix";
        string Config(ProviderConfiguration hosts)
        {
            UMC.ITME.WebServlet.IsHttps = UMC.Data.WebResource.Instance().Provider["scheme"] == "https";
            UMC.ITME.WebServlet.MainDomain = UMC.Data.WebResource.Instance().Provider["domain"] ?? "localhost";
            _urls.Clear();
            var host = new Dictionary<int, Socket[]>();

            var sb = new StringBuilder();
            foreach (var p in hosts.Providers)
            {
                switch (p.Type)
                {
                    case "unix":
                        if (Socket.OSSupportsUnixDomainSockets)
                        {

                            if (_host.ContainsKey(0) == false)
                            {
                                if (System.IO.Directory.Exists(UnixPath))
                                {
                                    System.IO.Directory.Delete(UnixPath, true);
                                }
                                if (System.IO.File.Exists(UnixPath))
                                {
                                    System.IO.File.Delete(UnixPath);
                                }
                                try
                                {
                                    var unix = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
                                    unix.Bind(new UnixDomainSocketEndPoint(UnixPath));
                                    unix.Listen(512);
                                    SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs();
                                    eventArgs.Completed += Unix;
                                    unix.AcceptAsync(eventArgs);
                                    host[0] = new Socket[] { unix };

                                    _urls.Add("unix://" + UnixPath);
                                }
                                catch (Exception ex)
                                {
                                    sb.Append($"Unix:{UnixPath} {ex.Message};");

                                }
                            }
                            else
                            {
                                _urls.Add("unix://" + UnixPath);
                                host[0] = _host[0];
                                _host.Remove(0);
                            }
                        }
                        break;
                    case "https":
                        {
                            int port = Utility.IntParse(p.Attributes["port"], 443);

                            try
                            {
                                if (_host.ContainsKey(port) == false)
                                {
                                    if (host.ContainsKey(port) == false)
                                    {
                                        var list = new List<Socket>();
                                        if (Socket.OSSupportsIPv4)
                                        {
                                            list.Add(BindSocket(new IPEndPoint(IPAddress.Any, port), Https));
                                        }
                                        if (Socket.OSSupportsIPv6)
                                        {
                                            list.Add(BindSocket(new IPEndPoint(IPAddress.IPv6Any, port), Https));
                                        }
                                        host[port] = list.ToArray();
                                    }
                                }
                                else
                                {
                                    host[port] = _host[port];
                                    _host.Remove(port);
                                }

                                _urls.Add($"https://*:{port}");


                            }
                            catch (Exception ex)
                            {
                                sb.Append($"Port:{port} {ex.Message};");
                            }
                        }
                        break;
                    case "tcp":
                        {
                            int port = Utility.IntParse(p.Attributes["port"], 5188);

                            try
                            {
                                var sever = p.Attributes["server"];
                                if (_host.ContainsKey(port) == false)
                                {
                                    if (host.ContainsKey(port) == false)
                                    {
                                        var s = sever.LastIndexOf(':');
                                        SocketProxyServier socketProxyServier = new SocketProxyServier(ProtocolType.Tcp, sever.Substring(0, s), Utility.IntParse(sever.Substring(s + 1), 5188));
                                        var list = new List<Socket>();
                                        if (Socket.OSSupportsIPv4)
                                        {
                                            list.Add(BindSocket(new IPEndPoint(IPAddress.Any, port), socketProxyServier.Accept));
                                        }
                                        if (Socket.OSSupportsIPv6)
                                        {
                                            list.Add(BindSocket(new IPEndPoint(IPAddress.IPv6Any, port), socketProxyServier.Accept));
                                        }
                                        host[port] = list.ToArray();
                                    }
                                }
                                else
                                {
                                    host[port] = _host[port];
                                    _host.Remove(port);
                                }

                                _urls.Add($"tcp://*:{port}");


                            }
                            catch (Exception ex)
                            {
                                sb.Append($"Port:{port} {ex.Message};");
                            }
                        }
                        break;
                    case "udp":
                        {
                            int port = Utility.IntParse(p.Attributes["port"], 5188);

                            try
                            {

                                var sever = p.Attributes["server"];
                                if (_host.ContainsKey(port) == false)
                                {
                                    if (host.ContainsKey(port) == false)
                                    {
                                        var s = sever.LastIndexOf(':');
                                        SocketProxyServier socketProxyServier = new SocketProxyServier(ProtocolType.Udp, sever.Substring(0, s), Utility.IntParse(sever.Substring(s + 1), 5188));
                                        var list = new List<Socket>();
                                        if (Socket.OSSupportsIPv4)
                                        {
                                            list.Add(BindSocket(new IPEndPoint(IPAddress.Any, port), ProtocolType.Udp, socketProxyServier.Accept));
                                        }
                                        if (Socket.OSSupportsIPv6)
                                        {
                                            list.Add(BindSocket(new IPEndPoint(IPAddress.IPv6Any, port), ProtocolType.Udp, socketProxyServier.Accept));
                                        }
                                        host[port] = list.ToArray();
                                    }
                                }
                                else
                                {
                                    host[port] = _host[port];
                                    _host.Remove(port);
                                }

                                _urls.Add($"udp://*:{port}");


                            }
                            catch (Exception ex)
                            {
                                sb.Append($"Port:{port} {ex.Message};");
                            }
                        }
                        break;
                    case "http":
                    default:
                        {
                            int port = Utility.IntParse(p.Attributes["port"], 80);

                            if (_host.ContainsKey(port) == false)
                            {
                                if (host.ContainsKey(port) == false)
                                {

                                    try
                                    {
                                        var list = new List<Socket>();
                                        if (Socket.OSSupportsIPv4)
                                        {
                                            list.Add(BindSocket(new IPEndPoint(IPAddress.Any, port), Http));
                                        }
                                        if (Socket.OSSupportsIPv6)
                                        {
                                            list.Add(BindSocket(new IPEndPoint(IPAddress.IPv6Any, port), Http));
                                        }
                                        host[port] = list.ToArray();
                                        _urls.Add($"http://*:{port}");

                                    }
                                    catch (Exception ex)
                                    {
                                        sb.Append($"Port:{port} {ex.Message};");
                                    }
                                }
                            }
                            else
                            {

                                host[port] = _host[port];
                                _host.Remove(port);
                                _urls.Add($"http://*:{port}");
                            }


                        }
                        break;
                }
            }
            foreach (var s in this._host.Values)
            {
                foreach (var v in s)
                {
                    v.Close();
                    v.Close();
                }
            }
            this._host.Clear();
            this._host = host;

            StartMsg = sb.ToString();
            return sb.ToString();

        }
        static HttpMimeServier httpMimeServier;
        bool IsStop = false;

        ManualResetEvent mre = new ManualResetEvent(false);
        public static void Start()
        {
            httpMimeServier = new HttpMimeServier();


            var webr = UMC.Data.WebResource.Instance();
            if (String.Equals(webr.Provider["webvpn"], "false") == false && String.IsNullOrEmpty(webr.Provider["appSecret"]) == false)
            {
                httpMimeServier.Bridge();

            }

            Pipe();


            Register(100, httpMimeServier);

            while (httpMimeServier.IsStop == false)
            {

                httpMimeServier.mre.WaitOne(10000);

                try
                {
                    CheckLink();
                    UMC.Net.NetProxy.Check();
                    HttpBridgeClient.Check();
                }
                catch (Exception ex)
                {
                    UMC.Data.Utility.Error("Server", DateTime.Now, ex.ToString());

                }
                var now = Utility.TimeSpan();

                int count = DoWorkers.Count;
                while (DoWorkers.TryDequeue(out var _top))
                {
                    if (_top.Item1 < now)
                    {
                        try
                        {
                            _top.Item2.DoWork();
                        }
                        catch (Exception ex)
                        {
                            UMC.Data.Utility.Error("Server", DateTime.Now, ex.ToString());
                        }
                    }
                    else
                    {
                        DoWorkers.Enqueue(_top);
                    }

                    count--;
                    if (count <= 0)
                    {
                        break;
                    }
                }

            }

            HotCache.Close();

            foreach (var s in httpMimeServier._host.Values)
            {
                foreach (var v in s)
                {
                    v.Close();
                    v.Close();
                }
            }
        }
        public static void Stop()
        {
            try
            {
                httpMimeServier.IsStop = true;
                HotCache.Close();
                try
                {
                    pipeServer.Close();
                }
                catch
                {

                }
                foreach (var s in httpMimeServier._host.Values)
                {
                    foreach (var v in s)
                    {
                        try
                        {
                            v.Close();
                            v.Close();
                        }
                        catch
                        {

                        }
                    }
                }
            }
            catch
            {

            }

        }
        // int CheckCertTime = 0;

        public static string Load(ProviderConfiguration config)
        {
            return httpMimeServier.Config(config);
        }
        // List
        static ConcurrentQueue<Tuple<int, IDoWorker>> DoWorkers = new ConcurrentQueue<Tuple<int, IDoWorker>>();
        public static void Register(int intervalTime, IDoWorker worker)
        {

            DoWorkers.Enqueue(Tuple.Create(Utility.TimeSpan() + intervalTime, worker));
        }
        // class CheckLicense : IDoWorker
        // {
        //     public void DoWork()
        //     {
        //         var tl = UMC.Proxy.DataFactory.Instance().SiteConfig();
        //         foreach (var t in tl)
        //         {
        //             if (t.IsCheck())
        //             {
        //             }
        //         }
        //         Register(3600, this);
        //     }
        // }
        // class Stoper : IDoWorker
        // {
        //     public void DoWork()
        //     {
        //         var secret = UMC.Data.WebResource.Instance().Provider["appSecret"];

        //         var webr = new Uri(APIProxy.Uri, "Transfer").WebRequest();

        //         UMC.Proxy.Utility.Sign(webr, secret);
        //         webr.Get(webr =>
        //         {
        //             webr.ReadAsString(json =>
        //             {
        //                 var meta = JSON.Deserialize<WebMeta>(json);
        //                 HttpServier.LicenseUsersSession = Utility.IntParse(meta["LicenseUsersSession"], 1000);
        //                 Data.Caches.ICacheSet cacheSet = UMC.Data.HotCache.Cache<UMC.Data.Entities.Session>();
        //                 if (cacheSet.Count > HttpServier.LicenseUsersSession)
        //                 {
        //                     httpMimeServier.IsStop = true;
        //                     httpMimeServier.mre.Set();
        //                 }

        //             }, r =>
        //             {
        //                 httpMimeServier.IsStop = true;
        //                 httpMimeServier.mre.Set();

        //             });
        //         });
        //     }
        // }
        String StartMsg;
        private HttpMimeServier()
        {

            sslServerAuthentication = new SslServerAuthenticationOptions()
            {
                ServerCertificateSelectionCallback = ServerCertificateSelectionCallback,
                CertificateRevocationCheckMode = X509RevocationMode.NoCheck,
                EncryptionPolicy = EncryptionPolicy.RequireEncryption,
                ClientCertificateRequired = false
            };

            HotCache.LoadFile();


            UMC.Web.WebResource.Instance(new UMC.ITME.WebResource(), UMC.Web.WebResource.Instance().Provider);

            var hosts = Reflection.Configuration("host");//?? new ProviderConfiguration();
            if (hosts.Count == 0)
            {
                var http = UMC.Data.Provider.Create("*", "http");
                http.Attributes["port"] = "80";
                hosts.Add(http);
                var ssl = UMC.Data.Provider.Create("ssl", "https");
                ssl.Attributes["port"] = "443";
                hosts.Add(ssl);
                Reflection.Configuration("host", hosts);
            }

            var logSb = new StringBuilder();
            logSb.Append(this.Config(hosts));
            var writer = new System.IO.StringWriter(logSb);
            UMC.Data.Sql.Initializer.Register(writer, new UMC.Data.Entities.Initializer(), new UMC.ITME.Entities.Initializer());
            writer.Flush();
            this.StartMsg = logSb.ToString();
            UMC.Net.APIProxy.Subscribes(_Server);


            var certs = Reflection.Configuration("certs");// ?? new ProviderConfiguration();
            foreach (var cert in certs.Providers)
            {
                try
                {
                    var x509 = X509Certificate2.CreateFromPem(cert["publicKey"], cert["privateKey"]);
                    Certificater.Certificates[cert.Name] = new Certificater { Name = cert.Name, Certificate = x509 };

                }
                catch
                {

                }
            }

        }
        private static void CheckSSl(string secret, string domain, bool isAuto)
        {
            UMC.ITME.Utility.Sign(new Uri(APIProxy.Uri, "Certificater").WebRequest(), secret).Post(new WebMeta().Put("type", isAuto ? "auto" : "apply", "domain", domain), webr =>
            {
                if (webr.StatusCode == System.Net.HttpStatusCode.OK)
                {
                    webr.ReadAsString(jsonStr =>
                   {
                       var hs = JSON.Deserialize<WebMeta>(jsonStr);
                       if (String.Equals(hs?["code"], "completed"))
                       {
                           UMC.ITME.Utility.Sign(new Uri(APIProxy.Uri, "Certificater").WebRequest(), secret)
                                 .Post(new WebMeta().Put("type", "cert", "domain", domain), UMC.ITME.Utility.Certificate);

                       }
                   });
                }
            });

        }


        private void Cert()
        {
            var secret = UMC.Data.WebResource.Instance().Provider["appSecret"];
            int nextIndex = 0;

            if (String.IsNullOrEmpty(secret) == false)
            {
                var now = Utility.TimeSpan(DateTime.Now.AddDays(5));
                while (nextIndex >= 0)
                {

                    var fs = HotCache.Find(new SiteCert(), false, 0, 500, out nextIndex);
                    foreach (var r in fs)
                    {
                        if ((r.IsApiumc ?? false) == false && String.IsNullOrEmpty(r.PrivateKey) == false && String.IsNullOrEmpty(r.PublicKey) == false)
                        {
                            if (r.ExpirationTime < now)
                            {
                                CheckSSl(secret, r.Domain, false);
                            }
                        }
                    };

                }
            }
        }
        private void Unix(object sender, SocketAsyncEventArgs eventArgs)
        {
            var client = eventArgs.AcceptSocket;
            eventArgs.AcceptSocket = null;
            do
            {
                switch (eventArgs.SocketError)
                {
                    case SocketError.OperationAborted:
                        return;
                    case SocketError.Success:
                        if (client != null)
                        {

                            new HttpMimeSocket(client, "127.0.0.1");
                        }
                        break;
                }
            } while (!Accept((Socket)sender, eventArgs));
        }
        private void Http(object sender, SocketAsyncEventArgs eventArgs)
        {
            do
            {
                var client = eventArgs.AcceptSocket;
                eventArgs.AcceptSocket = null;
                switch (eventArgs.SocketError)
                {
                    case SocketError.OperationAborted:
                        return;
                    case SocketError.Success:
                        if (client != null)
                        {
                            var ip = (client.RemoteEndPoint as IPEndPoint).Address;

                            new HttpMimeSocket(client, ip.ToString());

                        }
                        break;
                }
            } while (!Accept((Socket)sender, eventArgs));


        }
        private async void Https(Socket client)
        {

            SslStream sslStream = new SslStream(new NetworkStream(client, true), false);
            try
            {
                await sslStream.AuthenticateAsServerAsync(this.sslServerAuthentication);
                var ip = client.RemoteEndPoint as IPEndPoint;
                new HttpsMimeSocket(sslStream, ip.Address.ToString());

            }
            catch
            {
                sslStream.Close();
                sslStream.Dispose();
                client.Close();
                client.Dispose();
            }


        }
        private void Https(object sender, SocketAsyncEventArgs eventArgs)
        {
            do
            {
                var client = eventArgs.AcceptSocket;
                eventArgs.AcceptSocket = null;
                switch (eventArgs.SocketError)
                {
                    case SocketError.OperationAborted:
                        return;
                    case SocketError.Success:
                        if (client != null)
                        {
                            Https(client);
                        }
                        break;
                }
            } while (!Accept((Socket)sender, eventArgs));
        }
        bool Accept(Socket socket, SocketAsyncEventArgs eventArgs)
        {
            try
            {
                return socket.AcceptAsync(eventArgs);
            }
            catch
            {
                return true;
            }
        }
        bool isBridging = false;
        void Bridge()
        {
            isBridging = true;

            var secret = UMC.Data.WebResource.Instance().Provider["appSecret"];

            var webr = new Uri(APIProxy.Uri, "Transfer").WebRequest();

            UMC.ITME.Utility.Sign(webr, secret);
            webr.Get(webr =>
            {
                webr.ReadAsString(json =>
                {
                    isBridging = false;
                    var meta = JSON.Deserialize<WebMeta>(json);
                    if (meta.ContainsKey("domain") && meta.ContainsKey("ip"))
                    {
                        var scheme = meta["scheme"] ?? "http";
                        var ip = meta["ip"];
                        var domain = meta["domain"];
                        var bridgeUrl = $"{scheme}://{domain}";
                        var port = UMC.Data.Utility.IntParse(meta["port"], 0);

                        var provider = Data.WebResource.Instance().Provider;
                        if (String.Equals(provider.Attributes["bridge"], bridgeUrl) == false)
                        {
                            provider.Attributes["bridge"] = bridgeUrl;

                            var key = meta["key"];
                            var pdomain = provider["domain"];
                            if (String.IsNullOrEmpty(pdomain) || pdomain.StartsWith(key))
                            {
                                provider.Attributes["scheme"] = scheme;
                                provider.Attributes["domain"] = domain;
                                UMC.ITME.WebServlet.MainDomain = domain;
                            }
                        }

                        provider.Attributes["webvpn"] = "true";
                        var pc = Reflection.Configuration("assembly") ?? new ProviderConfiguration();
                        pc.Add(provider);
                        Reflection.Configuration("assembly", pc);

                        HttpBridgeClient.Start(meta["domain"], ip, port, 4);

                    }

                }, e => isBridging = false);
            });


        }
        static NamedPipeServerStream pipeServer;
        static async void Pipe()
        {
            using (pipeServer = new NamedPipeServerStream("APIUMC", PipeDirection.InOut))
            {
                var bufer = new byte[100];
                do
                {
                    var IsEror = false;

                    try
                    {
                        await pipeServer.WaitForConnectionAsync();

                        int l = pipeServer.Read(bufer, 0, 100);
                        var str = System.Text.Encoding.UTF8.GetString(bufer, 0, l).Split(' ');
                        switch (str[0])
                        {
                            case "reset":
                                {

                                    IsEror = true;

                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"正在使用异常重启ITME\r\n"));
                                }
                                break;
                            case "clear":
                                if (str.Length > 1)
                                {

                                    var user = Data.DataFactory.Instance().User(str[1]);
                                    var flags = user?.Flags ?? UMC.Security.UserFlags.Normal;
                                    if ((flags & Security.UserFlags.Lock) == Security.UserFlags.Lock)
                                    {
                                        flags ^= Security.UserFlags.Lock;

                                        Data.DataFactory.Instance().Put(new Data.Entities.User
                                        {
                                            Flags = flags,
                                            Username = user.Username,
                                            IsDisabled = false,
                                            ExpireTime = 0,
                                            Id = user.Id
                                        });
                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{str[1]}已解除锁定。\r\n"));
                                    }
                                    else
                                    {

                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{str[1]}未被锁定。\r\n"));
                                    }
                                }
                                else
                                {
                                    UMC.Data.Reflection.Instance().ClearCache();
                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes("配置缓存已经清空。\r\n"));
                                }
                                break;
                            case "biome":
                                if (str.Length > 1)
                                {
                                    var user = Data.DataFactory.Instance().User(str[1]);
                                    if (String.IsNullOrEmpty(user?.Biometric))
                                    {
                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{str[1]}生物特性未登记\r\n"));
                                        // this.Prompt("生物特征未登记");
                                    }
                                    else
                                    {
                                        var identity = UMC.Security.Membership.Instance().Identity(user.Id.Value);
                                        if (identity?.IsInRole(UMC.Security.Membership.AdminRole) == true)
                                        {
                                            UMC.Security.Membership.Instance().AddFlags(user.Username, Security.UserFlags.Biometric);
                                            pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{str[1]}生物特性已开通\r\n"));

                                        }
                                        else
                                        {
                                            pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"指令只支持快速开启管理员开启生物特性认证\r\n"));

                                        }
                                    }
                                }
                                else
                                {
                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes("biome指令需要带参数\r\n"));
                                    // pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(HttpBridgeClient.ServerChange(0)));
                                }
                                break;

                            case "vpn":
                                if (str.Length > 1)
                                {
                                    switch (str[1])
                                    {
                                        case "start":
                                            pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(HttpBridgeClient.ServerChange(2)));
                                            break;
                                        case "stop":
                                            pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(HttpBridgeClient.ServerChange(1)));
                                            break;
                                        default:
                                            pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"不支持“vpn {str[1]}”指令。\r\n"));
                                            break;
                                    }
                                }
                                else
                                {
                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(HttpBridgeClient.ServerChange(0)));
                                }
                                break;
                            case "https":
                                {

                                    var hosts = Reflection.Configuration("host");
                                    if (str.Length > 1)
                                    {

                                        if (Utility.IntParse(str[1], 0) > 0)
                                        {
                                            var http = UMC.Data.Provider.Create("ssl", "https");
                                            http.Attributes["port"] = str[1];

                                            hosts.Add(http);

                                            Reflection.Configuration("host", hosts);

                                        }

                                    }
                                    else
                                    {
                                        if (hosts.ContainsKey("ssl") == false)
                                        {
                                            var http = UMC.Data.Provider.Create("ssl", "https");

                                            http.Attributes["port"] = "443";

                                            hosts.Add(http);

                                            Reflection.Configuration("host", hosts);

                                        }
                                    }
                                    httpMimeServier.Config(Reflection.Configuration("host"));
                                }
                                goto default;
                            case "ssl":
                                {
                                    if (str.Length > 1)
                                    {
                                        var host = str[1];

                                        if (System.Text.RegularExpressions.Regex.IsMatch(host, @"^([a-z0-9\*]([a-z0-9\-]{0,61}[a-z0-9])?\.)+[a-z0-9]{1,6}$") == false)
                                        {
                                            pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"域名格式不正确。\r\n"));
                                            break;
                                        }

                                        var secret = UMC.Data.WebResource.Instance().Provider["appSecret"];
                                        if (String.IsNullOrEmpty(secret))
                                        {
                                            pipeServer.Write(System.Text.Encoding.UTF8.GetBytes("\a主体未登记，请在云桌面中完成登记\r\n"));
                                            break;
                                        }
                                        var webr2 = new Uri(APIProxy.Uri, "Certificater").WebRequest();
                                        UMC.ITME.Utility.Sign(webr2, secret);

                                        var webr = webr2.Post(new WebMeta().Put("type", "apply", "domain", host).Put("dcv", str.Length > 2 ? str[2] : null));

                                        var jsonStr = webr.ReadAsString();
                                        if (webr.StatusCode == System.Net.HttpStatusCode.OK)
                                        {
                                            var hs = JSON.Deserialize<WebMeta>(jsonStr);
                                            if (string.Equals(hs["code"], "success"))
                                            {
                                                pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(hs["msg"] ?? "\t\b正在签发证书,大约一分钟签发完成\r\n"));

                                            }
                                            else if (string.Equals(hs["code"], "completed"))
                                            {
                                                if (Certificater.Certificates.TryGetValue(host, out var _cert) == false || _cert.Certificate == null)
                                                {
                                                    webr2.Post(new WebMeta().Put("type", "cert", "domain", host), UMC.ITME.Utility.Certificate);
                                                }
                                                pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(String.Format("{0}\r\n\r\n强烈建议：请在\b云桌面->应用设置->网关服务\f中管理证书\r\n", hs["msg"])));

                                            }
                                            else
                                            {
                                                pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(String.Format("{0}\r\n\r\n强烈建议：请在\b云桌面->应用设置->网关服务\f中管理证书\r\n", hs["msg"])));

                                            }

                                        }
                                        else
                                        {
                                            pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(webr.ReadAsString() ?? $"请确保域名“{host}”解释到服务器，并开放80端口\r\n"));
                                        }

                                    }
                                    else
                                    {

                                        var now = UMC.Data.Utility.TimeSpan();
                                        var ls = Certificater.Certificates.Values.OrderBy(r =>
                                        {
                                            if (r.Certificate != null)
                                            {
                                                r.Time = Utility.TimeSpan(Convert.ToDateTime(r.Certificate.GetExpirationDateString()));

                                            }
                                            return r.Time;
                                        });
                                        var sb = new StringBuilder();
                                        sb.AppendLine("  过期\t\t\t\t证书");
                                        foreach (var r in ls)
                                        {
                                            sb.AppendLine($"{UMC.ITME.Utility.Expire(now, r.Time, "\a正在签发")}\t\t\t{r.Name}");
                                        }
                                        if (ls.Count() == 0)
                                        {
                                            sb.AppendLine("\t\t还未有证书");
                                        }
                                        else
                                        {
                                            sb.AppendLine();
                                            sb.AppendLine("强烈建议：请在\b云桌面->应用设置->网关服务\f中管理证书");
                                        }
                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(sb.ToString()));
                                    }

                                }
                                break;
                            case "check":
                                if (str.Length > 1)
                                {
                                    var key = UMC.Data.Utility.Parse36Encode(UMC.Data.Utility.IntParse(new Guid(UMC.Data.Utility.MD5(System.AppContext.BaseDirectory)))); ;

                                    if (String.Equals(key, str[1]) == false)
                                    {
                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"主程序目录：{UMC.Data.Utility.MapPath("~")}"));
                                    }
                                }
                                break;
                            case "http":
                            case "start":
                                if (str.Length > 1)
                                {
                                    if (Utility.IntParse(str[1], 0) > 0)
                                    {
                                        var http = UMC.Data.Provider.Create("*", "http");
                                        http.Attributes["port"] = str[1];

                                        var hosts = Reflection.Configuration("host");
                                        hosts.Add(http);

                                        Reflection.Configuration("host", hosts);

                                    }
                                }
                                httpMimeServier.Config(Reflection.Configuration("host"));
                                goto default;
                            case "stop":
                                pipeServer.Write(System.Text.Encoding.UTF8.GetBytes("正在停止ITME服务。\r\n"));
                                httpMimeServier.IsStop = true;
                                httpMimeServier.mre.Set();
                                return;
                            default:
                            case "info":
                                {

                                    var secret = UMC.Data.WebResource.Instance().Provider["appSecret"];
                                    var sb = new StringBuilder();

                                    if (String.IsNullOrEmpty(httpMimeServier.StartMsg) == false)
                                    {
                                        sb.AppendLine(httpMimeServier.StartMsg);
                                        httpMimeServier.StartMsg = String.Empty;
                                    }
                                    if (httpMimeServier._urls.Count > 0)
                                    {
                                        sb.Append("监听地址：\b");
                                        sb.AppendJoin("\f, \b", httpMimeServier._urls);
                                        sb.AppendLine();

                                        if (String.IsNullOrEmpty(secret))
                                        {
                                            sb.AppendLine($"Web VPN ：\a主体未登记\f，登记后，才可开启");
                                        }
                                        else if (HttpBridgeClient.IsRunning)
                                        {
                                            var bridge = UMC.Data.WebResource.Instance().Provider["bridge"];
                                            sb.AppendLine($"Web VPN ：\b{bridge}");
                                        }
                                        else if (httpMimeServier.isBridging)
                                        {
                                            var bridge = UMC.Data.WebResource.Instance().Provider["bridge"];
                                            sb.AppendLine($"Web VPN ：{bridge}  \a[连接中]");
                                        }
                                        else
                                        {
                                            sb.AppendLine($"Web VPN ：请用[vpn start]指令来开启");
                                        }


                                    }
                                    else
                                    {
                                        sb.AppendLine("监听地址：\a监听失败");
                                    }
                                    sb.AppendLine();

                                    if (String.IsNullOrEmpty(secret) == false)
                                    {
                                        var webr = new Uri(APIProxy.Uri, "Transfer").WebRequest();
                                        UMC.ITME.Utility.Sign(webr, secret);
                                        var xhr = webr.Get();
                                        if (xhr.StatusCode == HttpStatusCode.OK)
                                        {
                                            var meta = JSON.Deserialize<WebMeta>(xhr.ReadAsString()) ?? new WebMeta();
                                            var caption = meta["caption"];
                                            // var license = meta["license"];
                                            if (meta.ContainsKey("sign") && meta.ContainsKey("signKey"))
                                            {
                                                License.Put(meta["signKey"].Split(","), meta["sign"]);
                                            }

                                            if (String.IsNullOrEmpty(caption))
                                            {
                                                sb.AppendLine($"注册主体：\a主体未登记\f，请用网址登录云桌面->应用设置->安全注册中完成登记");
                                            }
                                            else
                                            {
                                                sb.AppendLine($"注册主体：\b{caption} ");
                                            }
                                        }
                                        else
                                        {
                                            if (xhr.Error != null)
                                            {
                                                sb.AppendLine($"接口异常：\a{xhr.Error.Message}");
                                            }
                                            else
                                            {
                                                sb.AppendLine($"接口异常：\a{xhr.ReadAsString()}");
                                            }
                                            sb.AppendLine();

                                        }
                                        var lic = License.GetLicense("UserSession", 1000);
                                        if (lic.Quantity > 0)
                                        {
                                            sb.AppendLine($"版权信息：\r{lic.Quantity}\f个会话规模使用授权");
                                        }
                                        else
                                        {
                                            sb.AppendLine($"版权信息：\b不限\f会话规模使用授权");
                                        }
                                        if (lic.ExpireTime > 0)
                                        {
                                            var sttr = "已过期";
                                            sb.AppendLine($"版权时效：\r{Utility.Expire(Utility.TimeSpan(), lic.ExpireTime, sttr)}");

                                        }

                                        Data.Caches.ICacheSet cacheSet = UMC.Data.HotCache.Cache<UMC.Data.Entities.Session>();
                                        if ((cacheSet.Count > lic.Quantity && lic.Quantity > 0) || (lic.ExpireTime > 0 && lic.ExpireTime < Utility.TimeSpan()))
                                        {
                                            sb.AppendLine();
                                            sb.AppendLine($"版权合规：当前会话规模\r已超\f限制，将会影响您的正常使用。");
                                        }
                                    }
                                    else
                                    {
                                        sb.AppendLine($"注册主体：\a主体未登记\f，请在云桌面->应用设置->安全注册中完成登记");

                                    }


                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(sb.ToString()));
                                }
                                break;
                            case "pool":
                                pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(Pool()));
                                break;
                        }
                    }
                    catch (SocketException)
                    {
                        break;
                    }
                    catch (Exception ex)
                    {
                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(ex.ToString()));
                    }
                    finally
                    {

                        pipeServer.Disconnect();
                    }
                    if (IsEror)
                    {
                        throw new ApplicationException("异常重启");
                    }

                } while (httpMimeServier.IsStop == false);
                // pipeServer.Close();

            }
        }

        static String Pool()
        {
            var _pool = Net.NetProxy.Pool;
            var sb = new StringBuilder();
            sb.AppendLine("Http Pools:");
            lock (_pool)
            {
                if (_pool.Count == 0)
                {
                    sb.AppendLine("\t\tEmpty");
                }
                else
                {
                    var p = _pool.GetEnumerator();

                    while (p.MoveNext())
                    {
                        sb.AppendFormat("{0}\t\t{2}\t\t{1}", p.Current.Value.Unwanted.Count, p.Current.Key, p.Current.Value.BurstError);
                        sb.AppendLine();
                    }
                }
            }
            return sb.ToString();
        }
        static void CheckLink()
        {
            var time = UMC.Data.Utility.TimeSpan();
            var ms = httpMimes.Values.ToArray();

            foreach (var b in ms)
            {
                try
                {

                    if ((b.ActiveTime + b.TimeOut) < time)
                    {
                        httpMimes.TryRemove(b.Id, out var link);
                        if (b.TimeOut > 30)
                        {
                            b.OutText(504, "Gateway Timeout");
                        }
                        else
                        {
                            b.Dispose();
                        }
                    }
                }
                catch
                {

                }
            }
            var ws = Host.HttpWebSocket.WebSockets.ToArray();
            foreach (var w in ws)
            {
                try
                {
                    if (w.ActiveTime + 60 < time)
                    {
                        w.Ping();

                    }
                }
                catch
                {

                }
            }

        }

        void IDoWorker.DoWork()
        {
            // this.Cert();
            var tl = UMC.ITME.DataFactory.Instance().SiteConfig();
            foreach (var t in tl)
            {
                if (t.IsCheck())
                {
                }
            }
            Register(3600, this);
        }


        internal static ConcurrentDictionary<int, HttpMime> httpMimes = new ConcurrentDictionary<int, HttpMime>();


        const string PrivateKey = @"-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAwqNWSHCnMNBI/7Pxmikm3/LdlJVX9AAIaPRDAghtISHAmJgl
t2L8KtQ6AcgECQy5DftU+fUjS/btPAskb9MxVIARv0UbGVKECgYtLIfhjfzI62nk
vO+eDBIBCDlSuR0I64pqvi9d5Q53wag0pbyQ1Car3IDe8yHQHj2EqJHGLVcVh7MG
TeTfjjsBCjpaPBlmVpTCZ28CaePmYyqEcuIGgBK0SxI/abkzNyTL9iwvxj6h9JEw
u1AXvOiXIIIzgglNTjET5yGYiNPfcTF6QpZEblQjrT4CTBR2RiIK0nT2D73h+ugx
xacF6xE2OmRa8vXEggHwcLtUtr1KM2Xhyx4DRQIDAQABAoIBACtwzxod4oLXieNg
IwU4OA/1oZS+/EFeHIJoOehjPxAM+3JTSt+yPPvGICgznwryBv9i3+Vl2/nhY7Np
/TjkFvd4Gf3pi5HMQ+IE3OI6dZH+IE3CdaXhiRHClu5h9N+R5mLDou1NnxQ3dW0I
gK+Y9W4UL3loXdo/6rZFHq2M04FcsYbEUwP0MLnaiVnX/h36du4YCncODWThatqP
8ALuRUm8sa4VyZsCZGGxz1UGAaRr9CK0asDuaDBa35YJpF941EIkFTi5bMBbykob
fkuR/VmFI3hGiMIncVFgBnp9fcuU88jQb8WBoLaYre4wa9NNvbCey/BslZQUuUYl
YJOaDeUCgYEA7KYbsTmmzVjlzfjy03U99oS2WtcmIBexGMEawLGGcjlhpUfSynEu
0m8L8ri+lY3ib196Ru0Em69fMcEYsSSf6LdZI5XMzOT2/7hFIsJd0uewsSDbiS1N
+i4zTdx7N2ycCi9HUHYfFy9W4iFUS2UzhDUwQIPuLnQy/udQbJG37s8CgYEA0o3L
dO144g9U5fuJOq3atAzDWrcurQdvCCjh2OHjh6y13Ua1nhYZ6/AD9+f6YDqbgneJ
YpSJLTYI82JvnDaSTK6j3ULzbJdW5zcHLsFf/8W06h0tehIeMia3NQy6gWEemUPq
PN0vKL+E1WL3jtCSMO1We098PPu0brSuYG6uUasCgYAVuhZ2ygU/ezb2FzIsKep7
dKnNY01zytkOncQYBvSCDjSh2RtITOXwmhNtwHp2/qTYdtqiIma26H4D8meS8/re
gd7kPn+kHC11QvTOASxeDbmSOaMOUCOFobJCJskFSKp24OpaP84Q8d63OjokBfGZ
5Mw+UB6RE0gPUSt4HFTXzwKBgDnV/TcnK/dcosNxrqZRryuZ/edjPg0FZ7hkEnWS
xv8zr9kSXT0JcSFgEpb8P8hDEQhrcW+EwZGLsDW6qlHMo68woY5bn6YKhDKK6Qws
zgPh+On+DcnkRCsee2C1GF4FoXQUNbl2QEf/I6vBvaKbJC0QZJsGoGfX9B4cv3F5
taR1AoGBAIpKbTrtsZ9Fh2fEfu3d8JQ04bgYvqUAAa9G01NSwxNHicPwr9LM95+b
GLqVYCSWVjQ+OeLJRVOUdnFYpJWwXwQYOsfpkLup4mgE0tSOv0MUxRwtdTR7Wukx
5qr++f9yy1BP+N7oP08YjH8byNBhHMkK+NnVqdA0C3JAzZCPOdc8
-----END RSA PRIVATE KEY-----";
        const string CertKey = @"-----BEGIN CERTIFICATE-----
MIICoTCCAYmgAwIBAgIJAO3qL3c6zg9nMA0GCSqGSIb3DQEBCwUAMA8xDTALBgNV
BAMTBGl0bWUwIBcNMjMxMDI2MTEwNTQ2WhgPMjA3MzEwMjYxMTA1NDZaMA8xDTAL
BgNVBAMTBGl0bWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCo1ZI
cKcw0Ej/s/GaKSbf8t2UlVf0AAho9EMCCG0hIcCYmCW3Yvwq1DoByAQJDLkN+1T5
9SNL9u08CyRv0zFUgBG/RRsZUoQKBi0sh+GN/MjraeS8754MEgEIOVK5HQjrimq+
L13lDnfBqDSlvJDUJqvcgN7zIdAePYSokcYtVxWHswZN5N+OOwEKOlo8GWZWlMJn
bwJp4+ZjKoRy4gaAErRLEj9puTM3JMv2LC/GPqH0kTC7UBe86JcggjOCCU1OMRPn
IZiI099xMXpClkRuVCOtPgJMFHZGIgrSdPYPveH66DHFpwXrETY6ZFry9cSCAfBw
u1S2vUozZeHLHgNFAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAFcVxZHuswUNJBk5
ZFn7+eIkpLvJ3Zn8y+jznOcJApSOsJ4t9l1Q9K66crwR+TvDHih78hp6jIfIw0NK
+ioXvffHkOqGrv1MHltFsA2fJmM73qOZwY2oOWB3Sxx7bl0D5icfW5BkigOBiXWI
ANMA/uLLjPPMV9xbIXG7jp4cNh5+Fxzo3Xf0FHkURmL1h+hEHD2FpnqAFoUq2ggT
foB4g9Tkmylif13s5+AdEpPTIN6SHUSHTtoTwz447U+rO8/534DeGQziXRsSTMkv
qwKdML5N3W9XcKRWLXXz+cWyf1/f9fED9mW1RzKSgpJORUSh2irbLIZMHlJ5gIP7
xIGN+sg=
-----END CERTIFICATE-----";
    }



}
